Skip to content

LT-22854: Control the Avalonia interface font from the theme - #1196

Open
johnml1135 wants to merge 7 commits into
mainfrom
LT-22854-andika-ui-font
Open

johnml1135 wants to merge 7 commits into
mainfrom
LT-22854-andika-ui-font

Conversation

@johnml1135

@johnml1135 johnml1135 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Start here: Src/Common/FwAvalonia/FwUiFont.cs selects the application-wide interface font stack from the theme and startup UI language.

Segoe UI is the default on Windows to preserve the density of the current interface. The stack adds named script fallbacks for the installer UI languages and ends with the platform default. The bundled Andika collection remains private; writing-system data continues to use its writing-system font.

The interface font is selected once for the application, so menus do not change with the open project. The UiElement style continues to govern UI-writing-system text drawn in Views; it does not set Avalonia chrome. The question for review is whether the chosen families cover the supported installations without clipping or missing glyphs.

Where to look

  • FwColorTokens.axaml and ADR 0004: Segoe UI density and the app-wide decision.
  • FwUiFont.FallbacksByLanguage: ordered Windows and SIL/Noto families.
  • FwUiFontTests: ordered family selection and sample shaping for the installer languages.

Not here: project-specific Avalonia interface fonts and line-height tokens. The nine dialog screenshots under Docs/migration/baseline-screenshots/ are regenerated with Segoe UI.

Verification (Windows/x64, at the font commit before a comment-only rewrap):

  • .\build.ps1 -CommentHygiene -TokenHygiene: passed. Comment hygiene passes at the head.
  • FwAvaloniaTests: 973 passed, 1 skipped, including all FwUiFontTests (ordered fallbacks for 14 languages and the sample-shaping cases).
  • FwAvaloniaDialogsTests: 289 passed. LexTextControlsTests (Avalonia): 42 passed.
  • Not run: the full test.ps1, and a live density and clipping check at other DPI settings.

Next: review the refreshed screenshots and the fallback table.


Fallbacks and evidence

The prior ADR recorded Andika's 1.61 em line metric against 1.33 em for Segoe UI. Line-height tokens remain deferred. The added cases cover ar, bn, km, ml, my, ne, ta, th and ur. Sample character maps were inspected in locally installed Windows font files, but that does not prove shaping or availability on every supported Windows installation. Khmer UI was not installed on the test machine, so Khmer falls through to Noto Sans Khmer or the platform default there; its family name is not verified against Microsoft's documentation.

🤖 Generated with Claude Code


This change is Reviewable

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

NUnit Tests

    1 files  ±  0      1 suites  ±0   15m 23s ⏱️ + 6m 49s
6 990 tests +174  6 905 ✅ +174  85 💤 ±0  0 ❌ ±0 
6 999 runs  +174  6 914 ✅ +174  85 💤 ±0  0 ❌ ±0 

Results for commit c276827. ± Comparison against base commit d0d85cb.

This pull request removes 9 and adds 183 tests. Note that renamed tests count towards both.
FwAvaloniaTests.LayoutImportCoverageTests ‑ ShippedLayouts_UnresolvedParts_AreExactlyTheLegacyUnresolvableSet
FwAvaloniaTests.XmlLayoutImporterDropDiagnosticsTests ‑ SublayoutElement_RaisesInfoDropDiagnostic
SIL.FieldWorks.FdoUi.DetailObjectInsertionTests ‑ IsOfferedOnEntry_AStemOrAffixAllomorph_FollowsTheFirstAllomorph
SIL.FieldWorks.FwCoreDlgs.FwFindReplaceDlgTests ‑ ApplyWS_ToSelectedString
SIL.FieldWorks.XWorks.AllomorphSectionCompositionTests ‑ Compose_EmptyAllomorphSection_ShowsGhostAddRow
SIL.FieldWorks.XWorks.DetailComposerTests ‑ Compose_GhostWithoutGhostField_IsNotEditable_SoTypingCannotCreateAndDiscard
SIL.FieldWorks.XWorks.DetailComposerTests ‑ Compose_SenseHeaders_UseHierarchicalNumbering_WithGlossSummary
SIL.FieldWorks.XWorks.LexiconMenuAuthorityTests ‑ AllomorphInserts_AreOfferedByTheEntrysMorphTypeAndFirstAllomorph
SIL.FieldWorks.XWorks.LexiconMenuExecutionTests ‑ InsertExtendedNote_FromTheSectionRow_GoesLast
FwAvaloniaDialogsTests.AddNewSenseDialogTests ‑ DialogText_UsesTheAndikaInterfaceFont
FwAvaloniaTests.DetailFocusMemoryTests ‑ RequestedObjectFocus_ScrollsToTheObjectsRow_InsteadOfKeepingTheOffset
FwAvaloniaTests.DetailPreviewTests ‑ Preview_WsText_KeepsWsFonts_WhileLabelsUseTheInterfaceFont
FwAvaloniaTests.DetailViewingParityTests ‑ CollapsibleHeader_ShowsItsCollapsedLine_OnlyWhileCollapsed
FwAvaloniaTests.DetailViewingParityTests ‑ LongHeaderLine_WrapsWithinThePane_WithTheBoxBesideItsFirstLine
FwAvaloniaTests.DetailViewingParityTests ‑ NormalWeightHeader_DrawsNoHeavyRule_AtTheTopLevel
FwAvaloniaTests.FwUiFontTests ‑ ApplyTo_CalledAgain_ChangesNothing
FwAvaloniaTests.FwUiFontTests ‑ BundledFaces_ResolveForEveryWeightInUse
FwAvaloniaTests.FwUiFontTests ‑ ContextMenuItem_InheritsTheInterfaceFont
FwAvaloniaTests.FwUiFontTests ‑ FallbackFamiliesFor_InvariantCultureHasNoNamedFamilies
…

♻️ This comment has been updated with latest results.

@codecov-commenter

codecov-commenter commented Oct 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.11321% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 40.36%. Comparing base (d0d85cb) to head (c276827).
⚠️ Report is 16 commits behind head on main.

Files with missing lines Patch % Lines
Src/Common/FwAvalonia/FwUiFont.cs 97.95% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1196      +/-   ##
==========================================
+ Coverage   39.88%   40.36%   +0.47%     
==========================================
  Files        1542     1551       +9     
  Lines      355361   355667     +306     
  Branches    41320    41480     +160     
==========================================
+ Hits       141753   143579    +1826     
+ Misses     184253   182777    -1476     
+ Partials    29355    29311      -44     
Files with missing lines Coverage Δ
Src/Common/FwAvalonia/Detail/FwFieldControls.cs 87.56% <100.00%> (ø)
Src/Common/FwAvalonia/FwAvaloniaApp.cs 82.35% <100.00%> (+1.10%) ⬆️
Src/Common/FwAvalonia/FwThemeResources.cs 69.23% <100.00%> (+2.56%) ⬆️
.../Common/FwAvaloniaTheme/Tokens/FwColorTokens.axaml 100.00% <100.00%> (ø)
Src/Common/FwAvalonia/FwUiFont.cs 97.95% <97.95%> (ø)

... and 95 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

johnml1135 and others added 4 commits October 23, 2026 07:05
The five faces in use (Regular, Italic, Bold, BoldItalic, SemiBold)
ship unmodified inside FwAvaloniaTheme.dll with the OFL text and a
notice recording the SHA-256 of each file. Nothing registers or uses
them yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The interface font is no longer left to the platform default. The
FwUiFontFamily token names it, FwUiFont registers the bundled font
collection and points Semi's DefaultFontFamily,
ContentControlThemeFontFamily and SemiFontFamilyRegular at a stack of
that font followed by the fallbacks the UI language needs. The default
is Andika; fa, hi, ko, te and zh-CN get a Windows system font first
and the SIL or Noto family second. The other UI languages are covered
by the default itself.

Data text keeps its writing-system font, and the writing-system
abbreviation column is measured in the interface font. The token
generator learns FontFamily entries. Tests cover each fallback
language's sample string. Two tests that built Avalonia controls on
the NUnit thread become AvaloniaTest, since the headless session owns
the dispatcher.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ADR 0004 records that the theme controls the interface font, Andika as
the proposed default and the alternatives, the Semi resource keys, the
five faces, the unchanged sizes and the per-language fallback fonts.
Two passages that still described the Fluent theme and its font now
name the Semi theme and the FieldWorks interface font.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nine committed dialog snapshots are regenerated with the interface
in Andika. Lines are about 3 px taller at 11 px, so rows and dialogs
grow a little; AssertNoCrowding still passes for every dialog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@johnml1135
johnml1135 force-pushed the LT-22854-andika-ui-font branch from f5874ae to 0921803 Compare October 23, 2026 11:29
@jasonleenaylor

Copy link
Copy Markdown
Contributor

So my first thought on looking at this is how it will interact with the users ability to choose the UI font from the styles dialog. I'll do a code review on it, but I wanted to capture my thoughts first.

@jasonleenaylor jasonleenaylor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The token mechanism is a good shape, but please don't let the default raise the line height. Interface density is a feature of FieldWorks that nearly all users value, and Andika's 1.61 em line against Segoe UI's 1.33 makes every row and dialog taller. Pick a default that keeps today's line height, or bring the line-height tokens the ADR defers into this PR. Users with limited vision who need larger or taller text should get it through the user font setting in the inline comment, not through the default.

This review was assisted by Claude Opus 5.5.

/// the order tried. A family that is not installed is skipped, so each list names a
/// Windows system font first and an SIL or Noto family second. Keyed by language code, so
/// every Chinese culture shares one list.</summary>
private static readonly Dictionary<string, string[]> FallbacksByLanguage =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FieldWorks already lets users choose a UI font: the UiElement style is listed in the Styles dialog (FwStylesDlg.cs:148 shows internal styles), with a font per writing system, and the WinForms views use it for UI text drawn in Views (FwBaseVc.MakeUiElementString, FilterBar.cs:930, the detail view's literal headings). Nothing in Avalonia reads it yet, and this table adds a second, fixed mechanism alongside it. It also misses ar, bn, km, ml, my, ne, ta, th and ur, which the installer ships (Installer.targets:98-127). The Avalonia interface font should integrate with that setting: take UiElement's font for the UI writing system, with the bundled font as the default when none is set, instead of a hard-coded fallback table.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've gone a different way on UiElement, deliberately. The interface font is chosen once at startup, from the theme and the UI language, and applies to the whole application. UiElement is a project style, so wiring it into Avalonia chrome would make menus and dialogs change font with whichever project is open. Avalonia's font resources are also application-wide, so a second project window would change the first. UiElement keeps its current job, UI-writing-system text drawn in Views, and writing-system text still uses its writing-system fonts. ADR 0004 records the decision.

The missing languages are fixed in c276827: ar, bn, km, ml, my, ne, ta, th and ur now have ordered fallbacks (Windows UI font first, then an SIL or Noto font, then the platform default). FwUiFontTests asserts the order for all 14 languages and shapes a sample for each. Those tests pass on Windows.

Larger text for users with limited vision isn't handled here. If it's needed, I'd make it an application-wide user setting rather than a project style.

johnml1135 and others added 3 commits October 29, 2026 12:07
Nine committed screenshots still showed the old Andika interface font.
Regenerate exactly those nine by running the Avalonia dialog tests and
copying the captures from Output/Snapshots, as the visual snapshot
testing guide describes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@johnml1135

Copy link
Copy Markdown
Contributor Author

On density: the default is Segoe UI again, so line height is back to today's 1.33 em. Line-height tokens are still deferred. The nine dialog screenshots under Docs/migration/baseline-screenshots/ are regenerated with Segoe UI. Build, FwAvaloniaTests, FwAvaloniaDialogsTests and the Avalonia LexTextControlsTests pass on Windows. I haven't checked clipping at other DPI settings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants